/***************************************************************
***************Base Parser for all LPMED grammars***************
***************************************************************/

parser grammar LPMEDParser;

options
{
	output = AST;
	ASTLabelType=CommonTree;
	language = CSharp2;
	tokenVocab = LPMEDLexer;
}

@header
{

	using System.Collections.Generic;
	using CommonClasses.Model;
	using CommonClasses.Services;
}

@members
{
	public List<Exception> Logger = new List<Exception>();
	public IFunctionManager functionManager = null;
	private int functionNesting = 0;
}

@namespace { Core.ANTLRGrammars }


block : (varDecListFixed)* blockStmt;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

varDecListFixed : VAR (varDecListAtom)+ -> varDecListAtom+ ;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

varDecListFree : VAR (ID (COMMA ID )* COLON TYPE SEMI) -> ^(CTYPE TYPE ID+);
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

varDecListAtom : (peremDecList COLON TYPE SEMI)  -> ^(CTYPE TYPE peremDecList) ;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

peremDecList : ID (COMMA ID )* ->ID+;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

blockStmt : CURLYOBRACKET (stmt)* CURLYCBRACKET	 -> ^(CSTATEMENT stmt*);
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

stmt
options { backtrack=false;}
:			assign SEMI -> assign
		|	ifStmt
		|	WHILE OBRACKET expr CBRACKET blockStmt -> ^(CWHILE expr blockStmt)
		|	FOR OBRACKET assign SEMI expr SEMI assign CBRACKET blockStmt -> ^(CFOR assign expr assign blockStmt)
		|	deviceMethodCall SEMI -> deviceMethodCall
		|	blockStmt
		|	BREAKPOINT OBRACKET INT CBRACKET SEMI -> ^(CBREAKPOINT INT)
		|	TERMINATEALL SEMI -> ^(CTERMINATEALL)
		|	functionCall SEMI -> functionCall
		| functionDefinition ->
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}


ifStmt
options { backtrack=true; }
		:
			IF OBRACKET expr CBRACKET THEN th=blockStmt ELSE el=blockStmt -> ^(CIFTE expr $th $el)
		|	IF OBRACKET expr CBRACKET THEN blockStmt -> ^(CIFTE expr blockStmt)
		;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}


assign 	:	ID EQUALS expr-> ^(CASSIGN ID expr) ;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}


expr 
			:	orExpr;
orExpr 			:	andExpr (OpOr^ andExpr)*;
andExpr			:	equalityExpr (OpAnd^ equalityExpr)* ;
equalityExpr		:	comparisonExpr (OpLogicalB^ comparisonExpr)* ;
comparisonExpr		:	additiveExpr (OpLogicalA^ additiveExpr)* ;
additiveExpr		:	multiplicativeExpr (OpAddSub^ multiplicativeExpr)* ;
multiplicativeExpr	:	notExpr (OpDivMul^ notExpr)*;
notExpr			:
				(OpUnar^ primary)
			|	primary
			;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

/*
negationExpr		:	
				(OpUnar primary -> ^(CUNARMIN primary))
			|	primary
			;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}
*/

primary			:	
				atom
			|	OBRACKET expr CBRACKET -> expr
			;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}


atom
options
{
	backtrack=true;
}	
:		ID -> ID
	|	FLOAT -> ^(CFLOAT FLOAT)
	| 	INT	-> ^(CINT INT)
	|	DBOOL	-> ^(CBOOL DBOOL)
	|	qualifiedName
	|	name=ID (DOT nodes+=ID )+ DOT STATE -> ^(CGETSTATE ^(OBJECTNAME $name) ^(NODES $nodes*))
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

qualifiedName	:
	name=ID (DOT nodes+=ID )+ DOT sm=ID -> ^(OBJECTNAME $name) ^(NODES $nodes*) ^(MEMBERNAME $sm )
;

deviceMemberID 	: 
			qualifiedName DOT GO 
				-> ^(CASYNCCALL qualifiedName)
		| 	qualifiedName DOT WAIT
				-> ^(CWAITTHECALL qualifiedName)
		|	qualifiedName DOT ENDPRESSURE
				-> ^(CENDTHECALL qualifiedName)
		| 	qualifiedName
				-> ^(CSYNCCALL qualifiedName)
		|	name=ID DOT sm=ID DOT GO 
				-> ^(CASYNCCALL ^(OBJECTNAME $name) ^(NODES ID) ^(MEMBERNAME $sm ))
		|	name=ID DOT sm=ID DOT WAIT
				-> ^(CWAITTHECALL ^(OBJECTNAME $name) ^(NODES ID) ^(MEMBERNAME $sm ))
		|	name=ID DOT sm=ID
				-> ^(CSYNCCALL ^(OBJECTNAME $name) ^(NODES ID) ^(MEMBERNAME $sm ))
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}


deviceMethodCall 	:	deviceMemberID OBRACKET CBRACKET -> ^(CCALL deviceMemberID);
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

functionCall 	: 
			functionSignature DOT GO OBRACKET CBRACKET
				-> ^(CASYNCFUNCCALL functionSignature)
		| 	functionSignature DOT WAIT OBRACKET CBRACKET
				-> ^(CWAITFUNCFINISH functionSignature)
		|	functionSignature OBRACKET CBRACKET
				-> ^(CSYNCFUNCCALL functionSignature)
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

functionSignature	:
	//ID -> ID
	ID OBRACKET parameterList? CBRACKET -> ID parameterList?
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

parameterList	:
	 pars+=parameter (COMMA pars+=parameter)* -> $pars+
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

parameter	: 
	parameterValue -> ^(PARAM parameterValue)
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

parameterValue	:
		ID 		-> ID
	| INT		-> INT
	|	qualifiedName	-> qualifiedName

;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

functionDefinition :
  DEFUN name = ID OBRACKET CBRACKET CURLYOBRACKET {functionNesting++;} body = functionBody CURLYCBRACKET
    {
	functionNesting--;
        if ((functionManager != null) && (functionNesting == 0))
            Logger.AddRange(functionManager.DefineFunction($name, $body.text));
    }
;
catch [Exception e] {Logger.Add(e); if (e is RecognitionException) Recover(input,(RecognitionException)e);}

functionBody :
   (stmt | varDecListFree)*
;
